﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using CRMAdminDashboard.CrmSvc;
using CRMAdminDashboard.CrmDisco;
using Microsoft.Crm.Passport.IdCrlWrapper;

namespace CRMAdminDashboard
{
    /// <summary>
    /// Code behind FormLogin
    /// </summary>
    public class HelperLogin : HelperBase
    {

        #region Constants

        private const string SDK_URL = "/MSCrmServices/2007/CrmService.asmx";
        private const string DISCOVERY_URL = "/MSCRMServices/2007/SPLA/CrmDiscoveryService.asmx";
        private const string LIVE_DISCOVERY_URL = "https://dev.crm.dynamics.com/MSCRMServices/2007/Passport/CrmDiscoveryService.asmx";
        private const string LIVE_PARTNER = "crm.dynamics.com";
        private const string LIVE_ENVIRONMENT = "Production";

        #endregion

        #region Fields

        /// <summary>
        /// The CRM Service handle
        /// </summary>
        private CachingCrmService _svcHandle;

        #endregion

        #region Properties

        /// <summary>
        /// The CRM Service handle
        /// </summary>
        public CachingCrmService SvcHandle
        {
            get
            {
                if (_svcHandle == null)
                {
                    _svcHandle = new CachingCrmService();
                }
                return _svcHandle;
            }
            set
            {
                _svcHandle = value;
            }
        }

        #endregion

        #region Entry Points

        /// <summary>
        /// Login using AD
        /// </summary>
        public static HelperLogin LoginIntranet(ref string url, string organization,
            string domain, string username, string pwd)
        {
            try
            {
                string parsedUrl = StripUrl(url);
                HelperLogin helper = new HelperLogin();

                url = parsedUrl + SDK_URL;

                CrmAuthenticationToken token = new CrmAuthenticationToken();
                token.AuthenticationType = 0;
                token.OrganizationName = organization;

                helper.SvcHandle.Url = url;
                NetworkCredential nc = new NetworkCredential(username, pwd, domain);
                helper.SvcHandle.CrmAuthenticationTokenValue = token;
                helper.SvcHandle.Credentials = nc;

                WhoAmI(helper, url, domain, username);

                return helper;
            }
            catch (Exception ex)
            {
                FormLogin.WriteLog(ex);
            }

            return null;
        }

        /// <summary>
        /// Login using forms authentication (IFD)
        /// </summary>
        public static HelperLogin LoginInternet(ref string url, string organization,
            string domain, string username, string pwd)
        {
            try
            {
                string parsedUrl = StripUrl(url);
                url = parsedUrl + DISCOVERY_URL;
                CrmDiscoveryService disco = new CrmDiscoveryService();
                disco.Url = url;

                RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest();
                orgRequest.UserId = domain + "\\" + username;
                orgRequest.Password = pwd;
                RetrieveOrganizationsResponse orgResponse = (RetrieveOrganizationsResponse)disco.Execute(orgRequest);

                foreach (OrganizationDetail orgDetail in orgResponse.OrganizationDetails)
                {
                    if (0 == string.Compare(orgDetail.OrganizationName, organization, true))
                    {
                        RetrieveCrmTicketRequest ticketRequest = new RetrieveCrmTicketRequest();
                        ticketRequest.OrganizationName = organization;
                        ticketRequest.UserId = domain + "\\" + username;
                        ticketRequest.Password = pwd;
                        RetrieveCrmTicketResponse ticketResponse = (RetrieveCrmTicketResponse)disco.Execute(ticketRequest);

                        CrmAuthenticationToken sdkToken = new CrmAuthenticationToken();
                        sdkToken.AuthenticationType = 2;
                        sdkToken.OrganizationName = organization;
                        sdkToken.CrmTicket = ticketResponse.CrmTicket;

                        HelperLogin helper = new HelperLogin();
                        helper.SvcHandle.CrmAuthenticationTokenValue = sdkToken;
                        helper.SvcHandle.Url = orgDetail.CrmServiceUrl;

                        WhoAmI(helper, orgDetail.WebApplicationUrl, domain, username);

                        return helper;
                    }
                }

                throw new ApplicationException("Organization not found (" + organization + ")");
            }
            catch (Exception ex)
            {
                FormLogin.WriteLog(ex);
            }

            return null;
        }

        /// <summary>
        /// Login using Live (CRM Online)
        /// </summary>
        public static HelperLogin LoginLive(string organization, string domain, string username, string pwd)
        {
            try
            {
                CrmDiscoveryService disco = new CrmDiscoveryService();
                disco.Url = LIVE_DISCOVERY_URL;

                OrganizationDetail orgDetail;
                CrmAuthenticationToken sdkToken = new CrmAuthenticationToken();
                sdkToken.AuthenticationType = 1;
                sdkToken.OrganizationName = organization;
                sdkToken.CrmTicket = GetCrmTicket(disco, username, pwd, organization, out orgDetail);
                HelperLogin helper = new HelperLogin();
                helper.SvcHandle.CrmAuthenticationTokenValue = sdkToken;
                helper.SvcHandle.Url = orgDetail.CrmServiceUrl;

                WhoAmI(helper, orgDetail.WebApplicationUrl, null, username);
                return helper;
            }
            catch (Exception ex)
            {
                FormLogin.WriteLog(ex);
            }

            return null;
        }

        /// <summary>
        /// Logout
        /// </summary>
        public void Logout()
        {
            FormLogin.WriteLog("Logged out." + Environment.NewLine);
        }

        #endregion

        #region Local Methods

        /// <summary>
        /// Get scheme and authority of URI
        /// </summary>
        private static string StripUrl(string url)
        {
            if (!url.StartsWith("http", StringComparison.CurrentCultureIgnoreCase))
            {
                url = "http://" + url;
            }

            Uri uri = new Uri(url);
            return uri.Scheme + "://" + uri.Authority;
        }

        /// <summary>
        /// Get CRM Ticket
        /// </summary>
        private static string GetCrmTicket(CrmDiscoveryService disco, string username, string pwd,
            string organization, out OrganizationDetail organizationDetail)
        {
            // Retrieve a policy from the Web service.
            RetrievePolicyResponse policyResponse = (RetrievePolicyResponse)disco.Execute(new RetrievePolicyRequest());

            // Retrieve a ticket from the Windows Live (Passport) service. 
            LogonManager lm = new LogonManager();
            string passportTicket = lm.Logon(username, pwd, LIVE_PARTNER, policyResponse.Policy, LIVE_ENVIRONMENT);

            // Dispose of the LogonManager object to avoid a FileNotOpen exception.
            lm.Dispose();

            // Retrieve a CrmTicket from the Web service.
            RetrieveCrmTicketRequest crmTicketRequest = new RetrieveCrmTicketRequest();
            crmTicketRequest.OrganizationName = organization;
            crmTicketRequest.PassportTicket = passportTicket;
            RetrieveCrmTicketResponse crmTicketResponse = (RetrieveCrmTicketResponse)disco.Execute(crmTicketRequest);
            organizationDetail = crmTicketResponse.OrganizationDetail;

            return crmTicketResponse.CrmTicket;
        }

        /// <summary>
        /// Print Who Am I
        /// </summary>
        private static void WhoAmI(HelperLogin helper, string url, string domain, string username)
        {
            FormLogin.WriteLog("Connecting to [" + url + "]" + Environment.NewLine);
            FormLogin.WriteLog("As " +
                (string)(string.IsNullOrEmpty(domain) ? "" : (domain + "\\")) +
                username + "..." + Environment.NewLine);

            WhoAmIResponse resp = (WhoAmIResponse)helper.SvcHandle.Execute(new WhoAmIRequest());

            organization org = (organization)helper.SvcHandle.Retrieve(EntityName.organization.ToString(), resp.OrganizationId, new AllColumns());
            businessunit bu = (businessunit)helper.SvcHandle.Retrieve(EntityName.businessunit.ToString(), resp.BusinessUnitId, new AllColumns());
            systemuser su = (systemuser)helper.SvcHandle.Retrieve(EntityName.systemuser.ToString(), resp.UserId, new AllColumns());

            FormLogin.WriteLog("Logged in." + Environment.NewLine);
            FormLogin.WriteLog("Organization: " + org.name + Environment.NewLine);
            FormLogin.WriteLog("Business Unit: " + bu.name + Environment.NewLine);
            FormLogin.WriteLog("User: " + su.fullname + Environment.NewLine + Environment.NewLine);
        }

        #endregion

    }
}
